package org.redmagic.service.controller;

import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.redmagic.Request;
import org.redmagic.location.web.JsonRedMagicRequest;
import org.redmagic.service.HierarchicalService;
import org.redmagic.service.threading.RedMagicHierarchicalAggregator;
import org.redmagic.service.threading.RedMagicHierarchicalSplitter;
import org.redmagic.service.utils.ServletUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.common.base.Stopwatch;

@RequestMapping("/bulk")
@Controller
public class BulkPropertyController {

	private static final Log LOG = LogFactory.getLog(BulkPropertyController.class);

	@Autowired
	private RedMagicHierarchicalSplitter splitter;

	@Autowired
	private HierarchicalService service;

	@RequestMapping(value = "*", method = RequestMethod.POST, consumes="application/json", produces="application/json")
	public @ResponseBody Properties retrieveProperties(HttpServletRequest request, @RequestBody JsonRedMagicRequest redMagicRequest) {
		try {
			Stopwatch stopWatch = new Stopwatch().start();
			String user = ServletUtils.getHostname(request);

			if (LOG.isDebugEnabled()) {
				LOG.debug("Bulk Property Request (" + user + "): " + redMagicRequest);
			}

			// split the request into multiple parts
			List<Request> hierarchicalRequests = this.splitter.split(redMagicRequest);

			// Create a new aggregator
			RedMagicHierarchicalAggregator aggregator = getAggregator(user);
			Map<String, String> resolvedProperties = aggregator.aggregate(hierarchicalRequests);
			Properties result = new Properties();
			result.putAll(resolvedProperties);

			if (LOG.isDebugEnabled()) {
				LOG.debug("Bulk Property Request (" + user + "): " + result);
			}

			if (LOG.isInfoEnabled()) {
				LOG.info("Bulk Request Total Time: " + stopWatch.elapsedMillis() + " (ms).");
				LOG.info("Resolved " + resolvedProperties.size() + " of " + hierarchicalRequests.size());
			}

			return result;
		} catch (Exception e) {
			LOG.error("CONTROLLER FAILED", e);
			throw new RuntimeException(e);
		}
	}

	private RedMagicHierarchicalAggregator getAggregator(String user) {
		RedMagicHierarchicalAggregator aggregator = new RedMagicHierarchicalAggregator();
		aggregator.setService(service);
		aggregator.setUser(user);
		return aggregator;
	}

	public HierarchicalService getService() {
		return service;
	}

	public void setService(HierarchicalService service) {
		this.service = service;
	}

	public RedMagicHierarchicalSplitter getSplitter() {
		return splitter;
	}

	public void setSplitter(RedMagicHierarchicalSplitter splitter) {
		this.splitter = splitter;
	}
}
